package ui;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TableTreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import os.MiniOS;
import os.MiniOSView;
import os.MiniProcess;
import os.MiniThread;
import util.TitansResourceBundle;
import actions.TitansAction;
import controls.TitansApplicationWindow;
import controls.TitansBrowser;
import controls.TitansComposite;

@SuppressWarnings("deprecation")
public class MiniOSPerspective extends TitansApplicationWindow implements
		MiniOSView
{

	private BootAction bootAction;
	private RestartAction restartAction;
	private ShutDownAction shutDownAction;
	private UserLoginAction userLoginAction;
	private UserLogoutAction userLogoutAction;

	private SuspendThreadAction suspendThreadAction;
	private ResumeThreadAction resumeThreadAction;
	private SuspendProcessAction suspendProcessAction;
	private ResumeProcessAction resumeProcessAction;
	private TerminateProcessAction terminateProcessAction;

	private TitansBrowser brwLog;
	private StyledText txtCommands;
	private Button btnSubmit;
	private ProcessesTableViewer tableViewer;

	private Display display;
	private MenuManager processesMenu;

	private String currentUser = "";

	@SuppressWarnings("unused")
	private String kernelProcessId = "";

	public MiniOSPerspective()
	{
		super(null, new Point(800, 600), TitansResourceBundle
				.getString("APP_TITLE"), "APP_ICON", null);
		MiniOS.getInstance().setView(this);
	}

	@Override
	protected void initActions()
	{
		bootAction = new BootAction();
		restartAction = new RestartAction();
		shutDownAction = new ShutDownAction();
		userLoginAction = new UserLoginAction();
		userLogoutAction = new UserLogoutAction();

		suspendThreadAction = new SuspendThreadAction();
		resumeThreadAction = new ResumeThreadAction();
		suspendProcessAction = new SuspendProcessAction();
		resumeProcessAction = new ResumeProcessAction();
		terminateProcessAction = new TerminateProcessAction();
	}

	protected MenuManager createMenuManager()
	{
		MenuManager menuManager = super.createMenuManager();

		MenuManager OSMenuManager = new MenuManager("OS");
		OSMenuManager.add(bootAction);
		OSMenuManager.add(restartAction);
		OSMenuManager.add(shutDownAction);
		OSMenuManager.add(new Separator());
		OSMenuManager.add(userLoginAction);
		OSMenuManager.add(userLogoutAction);
		menuManager.add(OSMenuManager);

		return menuManager;
	}

	protected ToolBarManager createToolBarManager(int style)
	{
		ToolBarManager toolBarManager = super.createToolBarManager(style);

		toolBarManager.add(bootAction);
		toolBarManager.add(restartAction);
		toolBarManager.add(shutDownAction);
		toolBarManager.add(new Separator());
		toolBarManager.add(userLoginAction);
		toolBarManager.add(userLogoutAction);

		return toolBarManager;
	}

	protected Control createContents(Composite parent)
	{
		parent = (Composite) super.createContents(parent);
		parent.setBackground(Display.getCurrent().getSystemColor(
				SWT.COLOR_WHITE));
		parent.setLayout(new GridLayout());

		display = Display.getCurrent();

		CTabFolder tabFolder = new CTabFolder(parent, SWT.BORDER);
		tabFolder.setLayout(new FillLayout());
		tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		tabFolder.setSimple(false);
		CTabItem tabItemLog = new CTabItem(tabFolder, SWT.NONE);
		tabItemLog.setText("Commands Log");
		TitansComposite cmpLog = new TitansComposite(tabFolder);
		tabItemLog.setControl(cmpLog);
		tabFolder.setMaximized(true);
		tabFolder.setSelection(0);

		Color titleForeColor = getShell().getDisplay().getSystemColor(
				SWT.COLOR_TITLE_FOREGROUND);
		Color titleBackColor1 = getShell().getDisplay().getSystemColor(
				SWT.COLOR_TITLE_BACKGROUND);
		Color titleBackColor2 = getShell().getDisplay().getSystemColor(
				SWT.COLOR_TITLE_BACKGROUND_GRADIENT);
		tabFolder.setSelectionForeground(titleForeColor);
		tabFolder.setSelectionBackground(new Color[]
		{ titleBackColor1, titleBackColor2 }, new int[]
		{ 100 }, true);

		cmpLog.setLayout(new GridLayout(2, false));

		brwLog = new TitansBrowser(cmpLog);
		GridData gData = new GridData(GridData.FILL_BOTH);
		gData.horizontalSpan = 2;
		brwLog.setLayoutData(gData);
		brwLog.setText("OS Shut Down");

		txtCommands = new StyledText(cmpLog, SWT.BORDER);
		txtCommands.setEditable(false);
		txtCommands.setLayoutData(new GridData(GridData.FILL_BOTH));

		btnSubmit = new Button(cmpLog, SWT.PUSH);
		btnSubmit.setText("Submit");
		btnSubmit.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
		btnSubmit.setEnabled(false);

		btnSubmit.addSelectionListener(new SelectionAdapter()
		{
			public void widgetSelected(SelectionEvent e)
			{
				txtCommands.forceFocus();
				MiniOS.getInstance().receiveUserCommand("user",
						txtCommands.getText());
				brwLog.appendText(txtCommands.getText() + "<br />");
				txtCommands.setText("");
				tableViewer.refresh();
			}
		});

		txtCommands.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				if (e.character == 13)
				{
					txtCommands.forceFocus();
					MiniOS.getInstance().receiveUserCommand("user",
							txtCommands.getText());
					brwLog.appendText(txtCommands.getText() + "<br />");
					txtCommands.setText("");
					tableViewer.refresh();
				}
			}
		});

		CTabItem tabItemMonitor = new CTabItem(tabFolder, SWT.NONE);
		tabItemMonitor.setText("Process Monitor");
		TitansComposite cmpMonitor = new TitansComposite(tabFolder);
		tabItemMonitor.setControl(cmpMonitor);
		cmpMonitor.setLayout(new FillLayout());

		tableViewer = new ProcessesTableViewer(cmpMonitor);
		tableViewer.setInput(MiniOS.getInstance().getProcessesList());

		shutDownAction.setEnabled(false);
		restartAction.setEnabled(false);
		userLoginAction.setEnabled(false);
		userLogoutAction.setEnabled(false);

		return parent;
	}

	@Override
	protected void runAction(PropertyChangeEvent e)
	{
		if ("bootOS".equals(e.getProperty()))
		{
			SchedulerDialog dlg = new SchedulerDialog(this.getShell());
			if(dlg.open() == Window.OK)
			{
				brwLog.setText( "OS Booting...<br />");
				txtCommands. setEditable(false);
				btnSubmit.setEnabled(false);
				bootAction.setEnabled(false) ;
				restartAction. setEnabled( true);
				shutDownAction. setEnabled( true);
				MiniOS.getInstance().boot(dlg.getScheduler(),dlg.getQuantum());
				tableViewer. refresh();
				loginUser();
			}
		}
		else if ("restartOS".equals(e.getProperty()))
		{
			brwLog.setText("OS Restarting...<br />");

			txtCommands.setEditable(false);
			btnSubmit.setEnabled(false);

			bootAction.setEnabled(false);
			restartAction.setEnabled(true);
			shutDownAction.setEnabled(true);
			// userLogoutAction.setEnabled(false);

			kernelProcessId = MiniOS.getInstance().restart();

			tableViewer.refresh();

			loginUser();
		}
		else if ("shutDownOS".equals(e.getProperty()))
		{
			brwLog.setText("OS Shuting Down...<br />");

			txtCommands.setEditable(false);
			btnSubmit.setEnabled(false);

			bootAction.setEnabled(true);
			restartAction.setEnabled(false);
			shutDownAction.setEnabled(false);
			userLoginAction.setEnabled(false);
			// userLogoutAction.setEnabled(false);

			MiniOS.getInstance().shutDown();
		}
		else if ("userLogin".equals(e.getProperty()))
		{
			loginUser();
		}
		else if ("userLogout".equals(e.getProperty()))
		{
			userLoginAction.setEnabled(true);
			// userLogoutAction.setEnabled(false);
			MiniOS.getInstance().userLogout(currentUser);
		}
		else if ("suspendThread".equals(e.getProperty()))
		{
			IStructuredSelection selection = (IStructuredSelection) tableViewer
					.getSelection();
			Object object = selection.getFirstElement();
			MiniThread thread = (MiniThread) object;
			MiniOS.getInstance().suspendThread(thread);
		}
		else if ("resumeThread".equals(e.getProperty()))
		{
			IStructuredSelection selection = (IStructuredSelection) tableViewer
					.getSelection();
			Object object = selection.getFirstElement();
			MiniThread thread = (MiniThread) object;
			MiniOS.getInstance().resumeThread(thread);
		}
		else if ("suspendProcess".equals(e.getProperty()))
		{
			IStructuredSelection selection = (IStructuredSelection) tableViewer
					.getSelection();
			Object object = selection.getFirstElement();
			MiniProcess process = (MiniProcess) object;
			MiniOS.getInstance().suspendProcess(process);
		}
		else if ("resumeProcess".equals(e.getProperty()))
		{
			IStructuredSelection selection = (IStructuredSelection) tableViewer
					.getSelection();
			Object object = selection.getFirstElement();
			MiniProcess process = (MiniProcess) object;
			MiniOS.getInstance().resumeProcess(process);
		}
		else if ("terminateProcess".equals(e.getProperty()))
		{
			IStructuredSelection selection = (IStructuredSelection) tableViewer
					.getSelection();
			Object object = selection.getFirstElement();
			MiniProcess process = (MiniProcess) object;
			MiniOS.getInstance().terminateProcess(process);
		}
	}

	private void loginUser()
	{
		UserLoginDlg dlg = new UserLoginDlg(this.getShell());
		if (dlg.open() == OK)
		{
			// check for the validation of the username and password
			if (MiniOS.getInstance().userLogin(dlg.getUsername(),
					dlg.getPassword()))
			{
				userLoginAction.setEnabled(false);
				// userLogoutAction.setEnabled(true);

				currentUser = dlg.getUsername();

				txtCommands.setEditable(true);
				btnSubmit.setEnabled(true);
				txtCommands.forceFocus();
			}
			else
			{
				userLoginAction.setEnabled(true);
				userLogoutAction.setEnabled(false);
			}
		}
		else
		{
			userLoginAction.setEnabled(true);
			userLogoutAction.setEnabled(false);
		}
	}

	public void refreshProcessesList()
	{
		display.asyncExec(new Runnable()
		{
			public void run()
			{
				tableViewer.refresh();
			}
		});
	}

	public void displayMessage(final String message)
	{
		display.asyncExec(new Runnable()
		{
			public void run()
			{
				if (brwLog.getText().length() > 5000)
				{
					brwLog.setText("");
				}
				brwLog.appendText(message + "<br />");

			}
		});
	}

	@Override
	protected void exitApplication()
	{
	}

	protected void handleShellCloseEvent()
	{
		System.exit(0);
	}

	private class BootAction extends TitansAction
	{
		public BootAction()
		{
			super(TitansResourceBundle.getString("Action.BOOT"), "bootOS",
					Action.AS_PUSH_BUTTON, "Action.BOOT", actionListener);
		}
	}

	private class RestartAction extends TitansAction
	{
		public RestartAction()
		{
			super(TitansResourceBundle.getString("Action.RESTART"),
					"restartOS", Action.AS_PUSH_BUTTON, "Action.RESTART",
					actionListener);
		}
	}

	private class ShutDownAction extends TitansAction
	{
		public ShutDownAction()
		{
			super(TitansResourceBundle.getString("Action.SHUT_DOWN"),
					"shutDownOS", Action.AS_PUSH_BUTTON, "Action.SHUT_DOWN",
					actionListener);
		}
	}

	private class UserLoginAction extends TitansAction
	{
		public UserLoginAction()
		{
			super(TitansResourceBundle.getString("Action.USER_LOGIN"),
					"userLogin", Action.AS_PUSH_BUTTON, "Action.USER_LOGIN",
					actionListener);
		}
	}

	private class UserLogoutAction extends TitansAction
	{
		public UserLogoutAction()
		{
			super(TitansResourceBundle.getString("Action.USER_LOGOUT"),
					"userLogout", Action.AS_PUSH_BUTTON, "Action.USER_LOGOUT",
					actionListener);
		}
	}

	private class SuspendThreadAction extends TitansAction
	{
		public SuspendThreadAction()
		{
			super("Suspend Thread", "suspendThread", Action.AS_PUSH_BUTTON,
					"Action.SUSPEND", actionListener);
		}
	}

	private class ResumeThreadAction extends TitansAction
	{
		public ResumeThreadAction()
		{
			super("Resume Thread", "resumeThread", Action.AS_PUSH_BUTTON,
					"Action.RESUME", actionListener);
		}
	}

	private class SuspendProcessAction extends TitansAction
	{
		public SuspendProcessAction()
		{
			super("Suspend Process", "suspendProcess", Action.AS_PUSH_BUTTON,
					"Action.SUSPEND", actionListener);
		}
	}

	private class ResumeProcessAction extends TitansAction
	{
		public ResumeProcessAction()
		{
			super("Resume Process", "resumeProcess", Action.AS_PUSH_BUTTON,
					"Action.RESUME", actionListener);
		}
	}

	private class TerminateProcessAction extends TitansAction
	{
		public TerminateProcessAction()
		{
			super("Terminate Process", "terminateProcess",
					Action.AS_PUSH_BUTTON, "Action.TERMINATE", actionListener);
		}
	}

	private class ProcessesTableViewer extends TableTreeViewer
	{
		public ProcessesTableViewer(Composite parent)
		{
			super(parent, SWT.FULL_SELECTION);
			Table table = getTableTree().getTable();
			table.setLinesVisible(true);
			table.setHeaderVisible(true);

			TableColumn col = new TableColumn(table, SWT.NONE);
			col.setText("ID");
			col.setWidth(75);

			col = new TableColumn(table, SWT.NONE);
			col.setText("Name");
			col.setWidth(100);

			col = new TableColumn(table, SWT.NONE);
			col.setText("User");
			col.setWidth(50);

			col = new TableColumn(table, SWT.NONE);
			col.setText("State");
			col.setWidth(70);

			col = new TableColumn(table, SWT.NONE);
			col.setText("Threads");
			col.setWidth(50);

			col = new TableColumn(table, SWT.NONE);
			col.setText("Description");
			col.setWidth(300);

			setLabelProvider(new ProcessesLabelProvider());
			setContentProvider(new ProcessesContentProvider());

			processesMenu = new MenuManager();
			Menu menu = processesMenu.createContextMenu(this.getControl());
			table.setMenu(menu);
			processesMenu.addMenuListener(new ProcessesMenuListener());
		}

	}

	private class ProcessesLabelProvider implements ITableLabelProvider
	{
		public void addListener(ILabelProviderListener listener)
		{
		}

		public void dispose()
		{
		}

		public Image getColumnImage(Object element, int columnIndex)
		{
			return null;
		}

		public boolean isLabelProperty(Object element, String property)
		{
			return false;
		}

		public void removeListener(ILabelProviderListener listener)
		{
		}

		public String getColumnText(Object element, int columnIndex)
		{
			if (element instanceof MiniProcess)
			{
				MiniProcess process = (MiniProcess) element;
				switch (columnIndex)
				{
				case 0:
					return process.getPid();
				case 1:
					return process.getName();
				case 2:
					return process.getUser();
				case 3:
					if (process.isSuspended())
					{
						return "Suspended";
					}
					return "Running";
				case 4:
					return process.getThreadCount() + "";
				case 5:
					return process.getDescription();
				}
			}
			else if (element instanceof MiniThread)
			{
				MiniThread thread = (MiniThread) element;
				switch (columnIndex)
				{
				case 0:
					return thread.getTid();
				case 1:
					return thread.getName();
				case 3:
					return thread.getThreadStateLiteral();
				case 5:
					return thread.getDescription();
				}
			}
			return "";
		}
	}

	private class ProcessesContentProvider implements ITreeContentProvider
	{
		public Object[] getChildren(Object obj)
		{
			if (obj instanceof MiniProcess)
			{
				MiniProcess process = (MiniProcess) obj;
				Hashtable<String, MiniThread> threads = process.getThreads();
				MiniThread[] threadsArray = new MiniThread[process
						.getThreadCount()];
				Iterator<Entry<String, MiniThread>> iterator = threads
						.entrySet().iterator();
				int i = 0;
				while (iterator.hasNext())
				{
					threadsArray[i++] = iterator.next().getValue();
				}
				return threadsArray;
			}
			return new Object[]
			{};
		}

		public Object getParent(Object obj)
		{
			if (obj instanceof MiniThread)
			{
				return ((MiniThread) obj).getProcess();
			}
			return null;
		}

		public boolean hasChildren(Object obj)
		{
			if (obj instanceof MiniProcess)
			{
				return ((MiniProcess) obj).getThreadCount() == 0 ? false : true;
			}
			return false;
		}

		@SuppressWarnings("unchecked")
		public Object[] getElements(Object inputElement)
		{
			if (inputElement instanceof Hashtable)
			{
				Hashtable<String, MiniProcess> processes = (Hashtable<String, MiniProcess>) inputElement;
				Enumeration<MiniProcess> e = processes.elements();
				MiniProcess[] processesArray = new MiniProcess[processes.size()];
				int i = 0;
				while (e.hasMoreElements())
				{
					processesArray[i++] = e.nextElement();
				}
				return (Object[]) processesArray;
			}
			return null;
		}

		public void dispose()
		{
		}

		public void inputChanged(Viewer arg0, Object arg1, Object arg2)
		{
		}
	}

	private class ProcessesMenuListener implements IMenuListener
	{
		@Override
		public void menuAboutToShow(IMenuManager arg0)
		{
			if (tableViewer.getSelection().isEmpty())
			{
				return;
			}

			processesMenu.removeAll();

			if (tableViewer.getSelection() instanceof IStructuredSelection)
			{
				IStructuredSelection selection = (IStructuredSelection) tableViewer
						.getSelection();
				Object object = selection.getFirstElement();

				if (object instanceof MiniProcess)
				{
					MiniProcess process = (MiniProcess) object;
					if (process.isSuspended())
					{
						processesMenu.add(resumeProcessAction);
					}
					else
					{
						processesMenu.add(suspendProcessAction);
					}
					processesMenu.add(terminateProcessAction);
				}
				else
				{
					MiniThread thread = (MiniThread) object;
					if (thread.getThreadState() == MiniThread.THREAD_SUSPENDED_READY
							|| thread.getThreadState() == MiniThread.THREAD_SUSPENDED_BLOCKED)
					{
						processesMenu.add(resumeThreadAction);
					}
					else
					{
						processesMenu.add(suspendThreadAction);
					}

				}
			}
		}
	}

	public static void main(String[] args)
	{
		TitansResourceBundle.createBundles("res/bundles.res");
		new MiniOSPerspective().run();
	}

}
